#include "stdafx.h"
#include "layouts.h"

namespace Imgui {
namespace Layouts
{
	void LayoutBase::Begin(const Window& window, uint32 flags)
	{
		m_window = window;
		m_separation = (flags & Imgui::NO_SEPARATION) ? 0 : m_pUi->style.margin;
		m_border = (flags & Imgui::BORDERLESS) ? 0 : max(m_separation, 1);
		m_flags = flags;
		m_layoutCounter = m_pUi->layoutCounter;
	}

	void LayoutBase::End()
	{
	}

	int LayoutBase::GetWidth() const 
	{
		return m_window.width;
	}

	int LayoutBase::GetHeight() const 
	{
		return m_window.height;
	}

//////////////////////////////////////////////////////////////////////

	void FixedWindow::Begin(const Window& window, uint32 flags)
	{
		LayoutBase::Begin(window, flags);
	}

	void FixedWindow::AddItem(uint32 flags, Window* pWindow)
	{
		int width = pWindow->width;
		int height = pWindow->height;

		if ((flags & EXPAND) || (flags & FIT))
		{
			*pWindow = m_window;
		}
		else if (flags & CENTRE)
		{
			pWindow->x = m_window.x + (m_window.width - width) / 2;
			pWindow->y = m_window.y + (m_window.height - height) / 2;
			pWindow->width = min(width, m_window.width);
			pWindow->height = min(height, m_window.height);
		}

		// clip
		int x1 = pWindow->x + pWindow->width;
		int y1 = pWindow->y + pWindow->height;

		pWindow->x = max(pWindow->x, m_window.x);
		pWindow->y = max(pWindow->y, m_window.y);
		pWindow->width = min(x1, m_window.x + m_window.width) - pWindow->x;
		pWindow->height = min(y1, m_window.y + m_window.height) - pWindow->y;
	}

///////////////////////////////////////////////////////////////

	void VerticalList::Begin(const Window& window, uint32 flags)
	{
		LayoutBase::Begin(window, flags);

		m_top = m_border;
		m_bottom = m_border;
		m_maxWidth = 0;
	}

	void VerticalList::AddItem(uint32 flags, Window* pWindow)
	{
		int indent = 0;
		int width = pWindow->width;
		int height = pWindow->height;

		if (flags & CENTRE)
		{
			pWindow->x = m_window.x + (m_window.width - width) / 2;
		}
		else if (flags & INDENT)
		{
			indent = pWindow->x;
			pWindow->x = m_window.x + pWindow->x + m_border;
		}
		else if (!(flags & USE_INPUT_XY))
		{
			pWindow->x = m_window.x + m_border;
		}
		else
		{
			pWindow->x = max(pWindow->x, m_window.x);
		}

		if (flags & EXPAND)
		{
			pWindow->width = m_window.width - m_border * 2;
		}
		else if (!(flags & USE_INPUT_XY))
		{
			pWindow->width = min(width, m_window.width);
		}
		else
		{
			pWindow->width = min(pWindow->width, m_window.x + m_window.width - pWindow->x);
		}

		if (flags & BACK)
		{
			pWindow->y = (m_window.y + m_window.height) - (m_bottom + height);
			m_bottom += height + m_separation;
			pWindow->height = min(height, m_window.height);
		}
		else if (flags & FIT)
		{
			pWindow->y = m_window.y + Top();
			pWindow->height = m_window.height - Top() - m_bottom - m_separation;
			m_top += height + m_separation;
		}
		else if (flags & USE_INPUT_XY)
		{
			pWindow->y = max(pWindow->y, m_window.y);
			pWindow->height = min(pWindow->height, m_window.y + m_window.height - pWindow->y);
		}
		else
		{
			pWindow->y = m_window.y + Top();
			pWindow->height = min(height, m_window.height - Top() - m_bottom);
			m_top += height + m_separation;
		}

		if (!(flags & USE_INPUT_XY))
			m_maxWidth = max(m_maxWidth, width + indent);
	}

	void VerticalList::End()
	{
		m_window.width = m_maxWidth + m_border * 2;
		m_window.height = m_top + m_bottom - m_separation;
	}

//////////////////////////////////////////////////////////////////

	void HorizontalList::Begin(const Window& window, uint32 flags)
	{
		LayoutBase::Begin(window, flags);

		m_left = m_border;
		m_right = m_border;
		m_maxHeight = 0;
		m_offset = 0;
	}

	void HorizontalList::AddItem(uint32 flags, Window* pWindow)
	{
		int width = pWindow->width;
		int height = pWindow->height;

		if (flags & CENTRE)
		{
			pWindow->y = m_window.y + (m_window.height - height) / 2;
		}
		else if (!(flags & USE_INPUT_XY))
		{
			pWindow->y = m_window.y + m_border;
		}

		if (flags & EXPAND)
		{
			pWindow->height = m_window.height - m_border * 2;
		}
		else if (m_flags & ALLOW_OVERFLOW)
		{
			pWindow->height = height;
		}
		else if (!(flags & USE_INPUT_XY))
		{
			pWindow->height = min(height, m_window.height);
		}

		if (flags & BACK)
		{
			pWindow->x = (m_window.x + m_window.width) - (m_right + width);
			m_right += width + m_separation;
			pWindow->width = min(width, m_window.width);
		}
		else if (flags & FIT)
		{
			pWindow->x = m_window.x + m_left;
			pWindow->width = m_window.width - m_left - m_right - m_separation;
			m_left += width + m_separation;
		}
		else if (flags & USE_INPUT_XY)
		{
			pWindow->x = max(pWindow->x, m_window.x);
			pWindow->width = min(pWindow->width, m_window.x + m_window.width - pWindow->x);
		}
		else
		{
			pWindow->x = m_window.x + m_left;
			pWindow->width = min(width, m_window.width - m_left - m_right);
			m_left += width + m_separation;
		}

		if (!(flags & USE_INPUT_XY))
			m_maxHeight = max(m_maxHeight, height);
	}

	void HorizontalList::End()
	{
		m_window.height = m_maxHeight + m_border * 2;
		m_window.width = m_right + m_left - m_separation - m_offset;
	}

////////////////////////////////////////////////////////////////////

	void Table::Begin(const Window& window, uint32 flags)
	{
		LayoutBase::Begin(window, flags);

		m_pUi->column = 0;
		m_pUi->row = 0;

		m_top = m_border;
		m_left = m_border;
	}

	void Table::AddItem(uint32 flags, Window* pWindow)
	{
		int width = pWindow->width;
		int height = pWindow->height;

		if ((int) m_layout.rows.size() == m_pUi->row)
		{
			if (!m_layout.rows.empty())
			{
				m_top += m_layout.rows.back().height;
				m_left = m_border;
			}

			m_layout.rows.emplace_back();
			m_layout.rows.back().x = m_window.x;
			m_layout.rows.back().y = m_window.y + m_border + m_top;
			m_layout.rows.back().width = m_window.width;
			m_layout.rows.back().height = 0;
		}

		if ((int) m_layout.columnWidth.size() == m_pUi->column)
		{
			m_layout.columnWidth.push_back(0);
		}

		Window& window = m_layout.rows[m_pUi->row];

		pWindow->y = window.y + m_border;
		pWindow->height = height;
		window.height = max(window.height, height);

		m_layout.columnWidth[m_pUi->column] = max(m_layout.columnWidth[m_pUi->column], width);

		int columnWidth = 0;

		if ((int) m_pLayout->columnWidth.size() > m_pUi->column)
			columnWidth = m_pLayout->columnWidth[m_pUi->column];

		pWindow->x = window.x + m_left;
		pWindow->width = min(columnWidth, window.width - m_left);
		m_left += columnWidth + m_separation;

		m_pUi->column++;
	}

	void Table::End()
	{
		m_top += m_layout.rows.back().height;

		m_layout.height = m_top - m_separation;
		m_layout.width = m_border * 2 - m_separation;

		for (int i = 0; i < (int) m_layout.columnWidth.size(); i++)
			m_layout.width += m_layout.columnWidth[i];

		*m_pLayout = m_layout;
		m_window = m_layout;
	}

}}